package com.ruoyi.project.applet.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.enums.PayStatus;
import com.ruoyi.common.utils.security.Md5Utils;
import com.ruoyi.common.utils.sign.Base64;
import com.ruoyi.common.utils.wx.WXPayUtil;
import com.ruoyi.project.applet.domain.*;
import com.ruoyi.project.applet.mapper.VipLevelMapper;
import com.ruoyi.project.applet.service.*;
import com.ruoyi.project.applet.util.AesUtil;
import com.ruoyi.project.system.domain.SysUserWx;
import com.ruoyi.project.system.service.ISysUserWxService;
import org.aspectj.weaver.ast.Or;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class WechatPayNewServer implements IWechatPayNewServer {

    private static final Logger logger = LoggerFactory.getLogger("WechatPayNewServer");

    @Value("${wx.mchkey}")
    private String mchkey;

    @Autowired
    ISysUserWxService userWxService;

    @Autowired
    IOrderService orderService;

    @Autowired
    IWallelogService logService;

    @Autowired
    IWalletService walletService;

    @Autowired
    IVipService vipService;

    @Value("${wx.wxAppId}")
    private String wxAppid;

    @Value("${wx.wxSecret}")
    private String wxSecret;

    @Value("${wx.mchid}")
    private String mchId;

    @Value("${wx.uploadShippingUrl}")
    private String uploadShippingUrl;

    @Autowired
    private RatioServiceImpl ratioService;

    @Autowired
    private VipLevelMapper vipLevelMapper;


    @Autowired
    RestTemplate restTemplate;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public String backPayOrder(HttpServletRequest request, HttpServletResponse response) {
        try (BufferedReader br = new BufferedReader(new InputStreamReader((ServletInputStream) request.getInputStream()))) {
            String line = null;
            StringBuilder sb = new StringBuilder();
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
            br.close();
            String notityXml = sb.toString();
            String resXml = "";
            Map map = WXPayUtil.xmlToMap(notityXml);
            String returnCode = (String) map.get("return_code");

            if ("SUCCESS".equals(returnCode)) {
                 if (true) {
               // if (WXPayUtil.isSignatureValid(WXPayUtil.mapToXml(map), mchkey)) {
                    logger.info("支付回调:[{}]", map);
                    //业务逻辑
                    String orderNumber = (String) map.get("out_trade_no");
                    final Order order = orderService.selectOrderByOrderNumber(orderNumber);
                    if (order == null) {
                        return "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                                + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
                    }
                    if (Integer.parseInt(order.getStatus()) >= 1) {
                        return "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                                + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
                    }

                    //将订单状态改为支付成功
                    Date date = new Date();
                    //会员设置到期时间
                    int goodId = order.getGoodId();
                    Vip vip = vipService.selectVipById(goodId);
                    SysUserWx sysUserWx = userWxService.selectSysUserWxByOpenId(order.getOpenId());
                    if (sysUserWx.getExpirationTime() == null) {
                        Date currentDate = new Date();
                        // 使用Calendar类来操作日期
                        Calendar calendar = Calendar.getInstance();
                        calendar.setTime(currentDate);
                        calendar.add(Calendar.DAY_OF_MONTH, vip.getDay()); // 加上30天

                        // 获取新的日期
                        Date newDate = calendar.getTime();
                        sysUserWx.setExpirationTime(newDate);
                    } else {
                        Date expirationTime = sysUserWx.getExpirationTime();
                        // 使用Calendar类来操作日期
                        Calendar calendar = Calendar.getInstance();
                        calendar.setTime(expirationTime);
                        calendar.add(Calendar.DAY_OF_MONTH, vip.getDay()); // 加上30天

                        // 获取新的日期
                        Date newDate = calendar.getTime();
                        sysUserWx.setExpirationTime(newDate);

                    }
                    sysUserWx.setIsVip(Constants.IS_VIP);
                    order.setStatus(PayStatus.PAY_SUCCESS.getName());
                    order.setPayTime(date);
                    orderService.updateOrder(order);

                    //增加抽奖点数
                    Wallet wallet = walletService.getWalletMoney(sysUserWx.getOpenId());
                    wallet.setNumber(wallet.getNumber() + vip.getNumber());
                    walletService.updateWallet(wallet);

                    //设置会员等级
                    String vipLevel = getVipLevel(sysUserWx);
                    sysUserWx.setVipLevel(vipLevel);
                    userWxService.updateSysUserWx(sysUserWx);
                    logger.info("会员:{},充值成功", sysUserWx.getUserId());

                    //分销
                    if (StringUtils.hasText(order.getFirstParent())) {
                        SysUserWx userWx = userWxService.selectSysUserWxByOpenId(order.getFirstParent());
                        //给一级分销人设置分销等级
                        String level = getVipLevel(userWx);
                        userWx.setVipLevel(level);
                        userWxService.updateSysUserWx(userWx);
                        //钱包余额加上分成
                        Wallet firstWaller = walletService.getWalletMoney(userWx.getOpenId());
                        List<Ratio> ratios = ratioService.selectRatioList(new Ratio());
                        String money = order.getPayAmount().multiply(ratios.get(0).getFirstRatio()).add(new BigDecimal(firstWaller.getMoney())).toString();
                        firstWaller.setMoney(money);
                        walletService.updateWallet(firstWaller);
                        //生成一条钱包记录
                        Wallelog wallelog = new Wallelog();
                        wallelog.setUserId(userWx.getOpenId());
                        wallelog.setAmount(order.getPayAmount().multiply(ratios.get(0).getFirstRatio()).toString());
                        wallelog.setType("0");
                        wallelog.setDescribe("一级分销提成");
                        wallelog.setOrderNumber(order.getNumber());
                        wallelog.setCreateTime(date);
                        logService.insertWallelog(wallelog);
                    }
                    if (StringUtils.hasText(order.getSecondParent())) {
                        SysUserWx userWx = userWxService.selectSysUserWxByOpenId(order.getSecondParent());
                        //钱包余额加上分成
                        Wallet secondWaller = walletService.getWalletMoney(userWx.getOpenId());
                        List<Ratio> ratios = ratioService.selectRatioList(new Ratio());
                        String money = order.getPayAmount().multiply(ratios.get(0).getSecondRatio()).add(new BigDecimal(secondWaller.getMoney())).toString();
                        secondWaller.setMoney(money);
                        walletService.updateWallet(secondWaller);
                        //生成一条钱包记录
                        Wallelog wallelog = new Wallelog();
                        wallelog.setUserId(userWx.getOpenId());
                        wallelog.setAmount(order.getPayAmount().multiply(ratios.get(0).getSecondRatio()).toString());
                        wallelog.setType("0");
                        wallelog.setDescribe("二级分销提成");
                        wallelog.setOrderNumber(order.getNumber());
                        wallelog.setCreateTime(date);
                        logService.insertWallelog(wallelog);
                    }

                    resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                            + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
                }
            } else {
                if (WXPayUtil.isSignatureValid(WXPayUtil.mapToXml(map), mchkey)) {
                    logger.info("ZF:[{}]", map);
                    //业务逻辑
                    String orderNumber = (String) map.get("out_trade_no");

                    final Order order = orderService.selectOrderByOrderNumber(orderNumber);
                    order.setStatus("-1");
                    orderService.updateOrder(order);
                }
                resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                        + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
            }

            BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
            out.write(resXml.getBytes());
            out.flush();
            out.close();
            return resXml;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public String getVipLevel(SysUserWx sysUserWx) {
        //查询自己归属于哪个等级
        List<VipLevel> vipLevels = vipLevelMapper.selectVipLevelList(new VipLevel());
        //查询一级分销订单是自己的有几个
        Order query = new Order();
        query.setFirstParent(sysUserWx.getOpenId());
        List<Order> orderList = orderService.selectOrderList(query);
        //根据userId去重
        if (!CollectionUtils.isEmpty(orderList)) {
            List<String> collect = orderList.stream().map(Order::getOpenId).distinct().collect(Collectors.toList());
            //获取分销人数
            int count = collect.size();
            for (VipLevel vipLevel : vipLevels) {
                if (count>=vipLevel.getUpNum()) {
                    if (vipLevel.getDownNum() != null) {
                        if (count<=vipLevel.getDownNum()) {
                            return vipLevel.getName();
                        }
                    } else {
                        return vipLevel.getName();
                    }
                }
            }
        }

        return vipLevels.get(0).getName();
    }

    @Override
    public String refundPayOrder(HttpServletRequest request, HttpServletResponse response) {
        try (BufferedReader br = new BufferedReader(new InputStreamReader((ServletInputStream) request.getInputStream()))) {

            String line = null;
            StringBuilder sb = new StringBuilder();
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
            br.close();
            String notityXml = sb.toString();


            final JSONObject jsonObject = JSON.parseObject(notityXml);
            final JSONObject resource = jsonObject.getJSONObject("resource");

            String associated_data = resource.getString("associated_data");
            String ciphertext = resource.getString("ciphertext");
            String nonce = resource.getString("nonce");
            JSONObject json = new JSONObject();

            try {
                String decryptData = new AesUtil(mchkey.getBytes(StandardCharsets.UTF_8)).decryptToString(associated_data.getBytes(StandardCharsets.UTF_8), nonce.getBytes(StandardCharsets.UTF_8), ciphertext);
                json = JSON.parseObject(decryptData);
            } catch (Exception e) {
                logger.error("", e);
            }

            String returnCode = json.getString("state");
            String resXml = "";
            if ("SUCCESS".equals(returnCode)) {
                logger.info("TK:[{}]", json);

                String out_bill_no = json.getString("out_bill_no");
                //业务逻辑

                final Wallelog wallelog = logService.selectWallelogByTradeNo(out_bill_no);
                wallelog.setStatus("1");
                logService.updateWallelog(wallelog);

                resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                        + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
            } else {
                resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                        + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
            }

            BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
            out.write(resXml.getBytes());
            out.flush();
            out.close();
            return resXml;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    public void shipping(Shipping shipping) {
        String accessToken = getAccessToken();
        String url = uploadShippingUrl + accessToken;
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(org.springframework.http.MediaType.APPLICATION_JSON);

        String outTradeNo = shipping.getOutTradeNo();
        String expressCompany = shipping.getExpressCompany();
        String openId = shipping.getOpenId();
        String trackingNo = shipping.getTrackingNo();
        JSONObject orderKey = new JSONObject();
        // 订单单号类型，用于确认需要上传详情的订单。枚举值1，使用下单商户号和商户侧单号；枚举值2，使用微信支付单号。
        orderKey.put("order_number_type", 1);
        orderKey.put("mchid", mchId);
        //orderKey.put("transaction_id",transactionId);
        orderKey.put("out_trade_no", outTradeNo);

        JSONObject shippingList = new JSONObject();
        //商品信息
        shippingList.put("item_desc", "课程");
        //物流单号，物流快递发货时必填
        shippingList.put("tracking_no", trackingNo);
        // 快递公司编码，物流快递发货时必填
        shippingList.put("express_company", expressCompany);

        JSONObject payer = new JSONObject();
        payer.put("openid", openId);

        JSONObject signObject = new JSONObject();
        JSONArray shipping_list = new JSONArray();
        shipping_list.add(shippingList);

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
        String uploadTime = simpleDateFormat.format(System.currentTimeMillis());

        signObject.put("order_key", orderKey);
        // 发货模式，发货模式枚举值：1、UNIFIED_DELIVERY（统一发货）2、SPLIT_DELIVERY（分拆发货） 示例值: 1
        signObject.put("delivery_mode", 1);
        // 物流模式，发货方式枚举值：1、实体物流配送采用快递公司进行实体物流配送形式 2、同城配送 3、虚拟商品，虚拟商品，例如话费充值，点卡等，无实体配送形式 4、用户自提
        signObject.put("logistics_type", 3);
        signObject.put("shipping_list", shipping_list);
        signObject.put("upload_time", uploadTime);
        signObject.put("payer", payer);

        // 构建包含请求体数据和请求头的HttpEntity对象
        HttpEntity<JSONObject> requestEntity = new HttpEntity<JSONObject>(signObject, headers);

        ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
        String body = responseEntity.getBody();
        JSONObject jsonObject = JSONObject.parseObject(body);
        if (jsonObject.getString("errcode") != null && !"0".equals(jsonObject.getString("errcode"))) {
            logger.error(jsonObject.toString());
        }
    }

    private String getAccessToken() {

        String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
        url = String.format(url, wxAppid, wxSecret);

        HttpEntity<String> httpEntity = new HttpEntity<>(new HttpHeaders());
        ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class);
        String response = responseEntity.getBody();
        JSONObject jsonObject = JSON.parseObject(response);

        return jsonObject.getString("access_token");
    }

    @Override
    public String refundPay(HttpServletRequest request, HttpServletResponse response) {

        logger.info("退款回调开始");
        try (BufferedReader br = new BufferedReader(new InputStreamReader((ServletInputStream) request.getInputStream()))) {

            String line = null;
            StringBuilder sb = new StringBuilder();
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
            br.close();
            String notityXml = sb.toString();
            logger.info(notityXml);
            String resXml = "";
            Map map = WXPayUtil.xmlToMap(notityXml);
            String returnCode = (String) map.get("return_code");

            if ("SUCCESS".equals(returnCode)) {
                //对回调内容进行解密
                String reqInfo = (String) map.get("req_info");
                byte[] bytes = Base64.decode(reqInfo);
                // byte[] bytes = Base64.decode(reqInfo);
                byte[] mchkeyByte = Md5Utils.hash(mchkey).toLowerCase().getBytes();
                SecretKeySpec key = new SecretKeySpec(mchkeyByte, "AES");
                Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
                cipher.init(Cipher.DECRYPT_MODE, key);
                String string = new String(cipher.doFinal(bytes), "utf-8");
                Map<String, String> resultMap = WXPayUtil.xmlToMap(string);
                String orderNumber = resultMap.get("out_trade_no");
                //申请退款金额
                String refundFee = resultMap.get("refund_fee");

                //业务逻辑
                Order order = orderService.selectOrderByOrderNumber(orderNumber);
                if (PayStatus.REFUND_SUCCESS.getName().equals(order.getStatus())) {
                    return "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                            + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
                }
                //               order.setStatus(PayStatus.REFUND_SUCCESS.getName());
                order.setRefundTime(new Date());
                orderService.updateOrder(order);
                logger.info("退款成功,订单号:{}", order.getNumber());


                resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                        + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
            } else {
                resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                        + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
            }
            BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
            out.write(resXml.getBytes());
            out.flush();
            out.close();
            return resXml;
        } catch (Exception e) {
            logger.error("微信退款回调异常", e.toString());
            throw new RuntimeException(e);
        }
    }

}
